package com.member.api;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang.StringUtils;
import sun.misc.BASE64Encoder;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 统一版签约H5加密规则Demo ---国际算法
 */
public class TestClientDataAndSignGuoJiDemo {
    private static final String IV = "union968";//加密向量保持一致

    public static void main(String[] args) {
        JSONObject json = new JSONObject();
        String key="xxxxxxxx";//商户秘钥，银联提供
        String clientData="";
        String signature="";
        try {
            String channelId="000000";//商户渠道，银联提供
            String timestamp= LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));//注意：必须是当前请求时间！
            String userName=URLEncoder.encode(encryptDESCBC("xxxxx",key));
            String cardId=URLEncoder.encode(encryptDESCBC("xxxxxxxx",key));
            String mobile="xxxxxx";//无值可以不拼接
            String cityCode="";//商户城市，银联提供 无值可以不拼接
            String bankCardNo="";//无值可以不拼接
            String cardType="";//无值可以不拼接
            String cardBin="";//无值可以不拼接
            String issInsCode="";//无值可以不拼接
            String returnUrl="";//无值可以不拼接
            String referralCode="";//无值可以不拼接

            //风险域：riskRateInfo所有必填字段，除了deviceLocation字段
            String deviceID="IMEI";//设备标识
            String deviceType="1";//设备类型
            String usrRgstrDt = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));//账户注册日期
            String accountIdHash="123456";//应用提供方账户ID
            String sourceIP="58.247.31.242";//IP 绑卡设备所在的公网IP
            String deviceLocation="+10/-20";//设备GPS位置 格式：为纬度/经度
            String deviceName="android";//设备型号
            String deviceSystem="1";//设备操作系统
            String usrLoginMethod="10000";//用户本次登录验证方式
            String usrLoginTime= LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));//用户本次登录时间
            String usrLoginMessageTime=LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));//用户最近登录短信验证通过时间
            String usrLoginFaceTime=LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));//用户最近登录人脸验证通过时间
            String usrLoginPasswordTime=LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS"));//用户最近登录支付密码验证通过时间
            String usrActivity="1";//用户活跃度
            String usrFrequentAreaCode="0000";//用户常用地
            //风险域拼接规则： {key=value&key=value&key=value}
            //注意：若deviceLocation该字段无值，则可以注释掉deviceLocation字符串的拼接
            String riskRateInfo = "{"+
                    "deviceID="+deviceID+
                    "&deviceType="+deviceType+
                    "&usrRgstrDt="+usrRgstrDt+
                    "&accountIdHash="+accountIdHash+
                    "&sourceIP="+sourceIP+
                    "&deviceLocation="+deviceLocation+
                    "&deviceName="+deviceName+
                    "&deviceSystem="+deviceSystem+
                    "&usrLoginMethod="+usrLoginMethod+
                    "&usrLoginTime="+usrLoginTime+
                    "&usrLoginMessageTime="+usrLoginMessageTime+
                    "&usrLoginFaceTime="+usrLoginFaceTime+
                    "&usrLoginPasswordTime="+usrLoginPasswordTime+
                    "&usrActivity="+usrActivity+
                    "&usrFrequentAreaCode="+usrFrequentAreaCode+
                    "}";//风险域
            riskRateInfo = new String(Base64.getEncoder().encode(riskRateInfo.getBytes(StandardCharsets.ISO_8859_1)), "UTF-8");


            //构建json
            json.put("channelId", channelId);// 渠道id，固定值，银联提供
            json.put("timestamp", timestamp);
            json.put("userName",userName);
            json.put("cardID",cardId);
            if(StringUtils.isNotEmpty(mobile)){//无值可以不拼接
                mobile=URLEncoder.encode(encryptDESCBC(mobile,key));
                json.put("mobile",mobile);
            }
            if(StringUtils.isNotEmpty(cityCode)){//无值可以不拼接
                json.put("cityCode",cityCode);
            }
            if(StringUtils.isNotEmpty(bankCardNo)){//无值可以不拼接
                bankCardNo=URLEncoder.encode(encryptDESCBC(bankCardNo,key));
                json.put("bankCardNo",bankCardNo);
            }
            if(StringUtils.isNotEmpty(cardType)){//无值可以不拼接
                json.put("cardType",cardType);
            }
            if(StringUtils.isNotEmpty(cardBin)){//无值可以不拼接
                json.put("cardBin",cardBin);
            }
            if(StringUtils.isNotEmpty(issInsCode)){//无值可以不拼接
                json.put("issInsCode",issInsCode);
            }
            if(StringUtils.isNotEmpty(returnUrl)){//无值可以不拼接
                returnUrl = new String(Base64.getEncoder().encode(returnUrl.getBytes(StandardCharsets.ISO_8859_1)), "UTF-8");
                json.put("returnUrl",returnUrl);
            }
            if(StringUtils.isNotEmpty(referralCode)){//无值可以不拼接
                json.put("referralCode",referralCode);
            }
            json.put("riskRateInfo",riskRateInfo);

            //构建clientData
            String string = "channelId="+channelId+
                    "&timestamp="+timestamp+
                    "&userName="+userName+
                    "&cardID="+cardId;
            if(StringUtils.isNotBlank(mobile)){//无值可以不拼接
                string = string.concat("&mobile=").concat(mobile);
            }
            if(StringUtils.isNotBlank(cityCode)){//无值可以不拼接
                string = string.concat("&cityCode=").concat(cityCode);
            }
            if(StringUtils.isNotBlank(bankCardNo)){//无值可以不拼接
                string = string.concat("&bankCardNo=").concat(bankCardNo);
            }
            if(StringUtils.isNotBlank(cardType)){//无值可以不拼接
                string = string.concat("&cardType=").concat(cardType);
            }
            if(StringUtils.isNotBlank(cardBin)){//无值可以不拼接
                string = string.concat("&cardBin=").concat(cardBin);
            }
            if(StringUtils.isNotBlank(issInsCode)) {//无值可以不拼接
                string = string.concat("&issInsCode=").concat(issInsCode);
            }
            if(StringUtils.isNotBlank(returnUrl)){//无值可以不拼接
                string = string.concat("&returnUrl=").concat(returnUrl);
            }
            if(StringUtils.isNotBlank(referralCode)){//无值可以不拼接
                string = string.concat("&referralCode=").concat(referralCode);
            }
            string = string.concat("&riskRateInfo=").concat(riskRateInfo);

            System.out.println("入参："+string);
            //使用Base64格式编码获取接口上送参数
            clientData = new String(Base64.getEncoder().encode(string.getBytes(StandardCharsets.ISO_8859_1)), "UTF-8");
            //生成签名
            signature = generateSignature(JSON.toJSONString(json), key);


            String url="http://58.33.119.64/medical/mobileapp/v3/yhfManager/toH5Bind?clientData="+clientData+"&signature="+signature;
            System.out.println("出参-生成的链接地址url:"+url);

        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }


    /**
     * DESCBC加密
     * @param src 数据源
     * @param key 密钥，长度必须是8的倍数
     * @return 返回加密后的数据
     * @throws Exception
     */
    public static String encryptDESCBC(final String src, final String key) throws Exception {
        // --生成key,同时制定是des还是DESede,两者的key长度要求不同
        final DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8"));
        final SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
        final SecretKey secretKey = keyFactory.generateSecret(desKeySpec);
        // --加密向量
        final IvParameterSpec iv = new IvParameterSpec(IV.getBytes("UTF-8"));
        // --通过Chipher执行加密得到的是一个byte的数组,Cipher.getInstance("DES")就是采用ECB模式,cipher.init(Cipher.ENCRYPT_MODE,
        // secretKey)就可以了.
        final Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv);
        final byte[] b = cipher.doFinal(src.getBytes("UTF-8"));

        // --通过base64,将加密数组转换成字符串
        final BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(b);
    }

    /**
     * 生成验签内容
     * @return
     */
    public static String generateSignature(String json, String authorizationKey) {
        String sign = null;
        try {
            sign = encode(JSONObject.parseObject(json), authorizationKey);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return sign;
    }

    private static String PARAM_AND_CHAR = "&";
    private static String PARAM_ASSIGN_CHAR = "=";

    /**
     * @param requestData 参数
     * @param authorizationKey 银联智慧医疗云平台Authorization Key
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String encode(Map<String, Object> requestData, String authorizationKey) throws NoSuchAlgorithmException {
        String sortRespJson = buildSortJson(requestData) + authorizationKey;
        return md5(sortRespJson);
    }

    private static String buildSortJson(Map<String, Object> requestData) {
        StringBuffer sortSb = new StringBuffer();
        List<String> jsonKeys = new ArrayList<>();
        for (String key : requestData.keySet()) {
            jsonKeys.add(key);
        }
        Collections.sort(jsonKeys);
        for (String jsonKey : jsonKeys) {
            if (requestData.get(jsonKey) != null && requestData.get(jsonKey) != "") {
                if (sortSb.length() > 0) {
                    sortSb.append(PARAM_AND_CHAR);
                }
                sortSb.append(jsonKey).append(PARAM_ASSIGN_CHAR).append(requestData.get(jsonKey));
            }
        }
        return sortSb.toString();
    }
    /** 获得MD5加密算法 **/
    private static String md5(String inStr){
        String result = "";
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
            // 这句是关键
            md5.update(inStr.getBytes("UTF-8"));
        } catch (NoSuchAlgorithmException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        byte b[] = md5.digest();
        int i;
        StringBuffer buf = new StringBuffer("");
        for (int offset = 0; offset < b.length; offset++) {
            i = b[offset];
            if (i < 0) {
                i += 256;
            }
            if (i < 16) {
                buf.append("0");
            }
            buf.append(Integer.toHexString(i));
        }
        result = buf.toString();

        return result;
    }
}
